/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.sales.generics.client.utils.numbers;

import com.google.gwt.event.dom.client.KeyCodes;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.logical.shared.ValueChangeEvent;
import com.google.gwt.event.logical.shared.ValueChangeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.i18n.client.NumberFormat;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.HasValue;
import com.google.gwt.user.client.ui.TextBox;

/**
 *
 * @author v
 */
public class DecimalBox extends Composite implements HasValue<Object> {

    /**
     * The NumberFormat used to formet text in the Box, and for parsing
     */
    private static final String NUMBER_PATTERN = "#########.#########";
    private static NumberFormat NUMBER_FORMAT = NumberFormat.getFormat(NUMBER_PATTERN);

    private static final String DECIMAL_SEPARATOR = ",";
    private static final String THOUSANDS_SEPARATOR = ".";

    /**
     * The TextBox Widget that is being wrapped to handle Numbers
     */
    private final TextBox box = new TextBox();

    /**
     * Construct a new DecimalBox which can be used to bind Decimal values to
     * the UI
     */
    public DecimalBox() {
        this(NUMBER_PATTERN);
    }

    /**
     * Construct a new DecimalBox with a specific NumberFormat
     *
     * @param format
     */
    public DecimalBox(String format) {
        NUMBER_FORMAT = NumberFormat.getFormat(format);
        box.addKeyPressHandler(new NumbersOnly());
        initWidget(box);
    }

    public void setMaxLength(int length) {
        box.setMaxLength(length);
    }

    public HandlerRegistration addKeyPressHandler(KeyPressHandler handler) {
        return addDomHandler(handler, KeyPressEvent.getType());
    }

    /**
     * Returns the value in the TextBox as a Double
     */
    @Override
    public String getValue() {
        if (box.getText() != null && !"".equals(box.getText())) {
//            Object value = adjustValueByType(box.getText());
            return box.getText();
        } else {
            return null;
        }
    }

    /**
     * Sets the value in the text box to be the Double value passed
     */
    @Override
    public void setValue(Object value) {
        setValue(value, true);
    }

    public void cancelKey() {
        box.cancelKey();
    }

    class NumbersOnly implements KeyPressHandler {

        @Override
        public void onKeyPress(KeyPressEvent event) {
            int keyCode = event.getNativeEvent().getKeyCode();
            if ((!Character.isDigit(event.getCharCode()))
                    && (keyCode != KeyCodes.KEY_TAB)
                    && (keyCode != KeyCodes.KEY_BACKSPACE)
                    && (keyCode != KeyCodes.KEY_DELETE)
                    && (keyCode != KeyCodes.KEY_HOME)
                    && (keyCode != KeyCodes.KEY_END)
                    && (keyCode != KeyCodes.KEY_LEFT)
                    && (keyCode != KeyCodes.KEY_UP)
                    && (keyCode != KeyCodes.KEY_RIGHT)
                    && (keyCode != KeyCodes.KEY_DOWN)
                    && (event.getCharCode() != '.')
                    && (event.getCharCode() != '-')) {
                ((TextBox) event.getSource()).cancelKey();
            } else {
                box.setText(((TextBox) event.getSource()).getText());
            }
        }
    }

    /**
     * Sets the value in the text box to be the Double value passed
     */
    @Override
    public void setValue(Object value, boolean fireEvents) {
        if (value == null) {
            box.setText(null);
        } else {
            value = adjustValueByType(value);
            box.setText(value.toString());
        }
    }

    public void setReadOnly(boolean readOnly) {
        box.setReadOnly(readOnly);
    }

    /**
     * Add value change Handler
     */
    @Override
    public HandlerRegistration addValueChangeHandler(ValueChangeHandler<Object> handler) {
        return addHandler(handler, ValueChangeEvent.getType());
    }

    /**
     * Enable/Disable the TextBox
     *
     * @param enabled
     */
    public void setEnabled(boolean enabled) {
        box.setEnabled(enabled);
    }

    private Object adjustValueByType(Object value) {
        if (value == null) {
            return 0D;
        }
        if (value instanceof String && !((String) value).isEmpty()) {
            value = ((String) value).replace(THOUSANDS_SEPARATOR, DECIMAL_SEPARATOR);
        }
        if (value instanceof Double) {
            if (Math.ceil((Double) value) == ((Double) value).intValue()) {
                value = String.valueOf(((Double) value).intValue());
            } else {
                value = NUMBER_FORMAT.format((Double) value).replace(THOUSANDS_SEPARATOR, DECIMAL_SEPARATOR);
            }
        }
        return value;
    }
}
